//#include <Windows.h>
#include <time.h>
//#include <sys/timerfd.h>
#include <fcntl.h>
#include <time.h>
#include <stdio.h>
#include <string.h>
//#include <unistd.h>

#include <iostream>
#include <vector>
#include <queue>

#include <_time.h>
#include <mutex.h>
#include <cstdcall.h>

#include <fmt.h>

#undef  _WIN32_WINNT
#define _WIN32_WINNT  0x0500


namespace cstdcall{
	namespace _time{
		using namespace std;





		class TimerQueue;
		typedef std::tr1::shared_ptr<TimerQueue>	TimerQueueRef;


		static TimerQueueRef	timerQueue = nullptr;

		class TimerQueue{
		public:

			TimerQueue():m_TimerQueueFd(nullptr)
			{
				m_TimerQueueFd = CreateTimerQueue();
			}

			~TimerQueue()
			{
				DeleteTimerQueue(m_TimerQueueFd);
			}

		public:
			friend void Init();

			TimerRef NewTimer(Duration d, TimerFunc f, void *arg, error_t &err)
			{
				err = nullptr;
				TimerRef		timer(new Timer());

				timer->r.when = d / (1000 * 1000);
				timer->r.func = f;
				timer->r.arg = arg;
				timer->thisP = timer;

				// Set a timer to call the timer routine in 10 seconds.
				if (!CreateTimerQueueTimer( &timer->r.timerfd, m_TimerQueueFd, 
					(WAITORTIMERCALLBACK)&TimerQueue::timer_do_func, timer.get() , (DWORD)timer->r.when, 0, 0)){
					err.reset(new Error(fmt::Sprintf("CreateTimerQueueTimer failed (%d)\n", GetLastError())));
					return nullptr;
				}


				return timer;
			}

			void StopTimer(const Timer &timer, error_t &err)
			{
				err = nullptr;

				if (DeleteTimerQueueTimer(m_TimerQueueFd, timer.r.timerfd, INVALID_HANDLE_VALUE) == FALSE){
					err.reset(new Error(fmt::Sprintf("DeleteTimerQueueTimer failed (%d)\n", GetLastError())));
				}
			}

		private:
			static void timer_do_func(void *arg, bool fired)
			{
				Timer		*t = (Timer *)arg;
				TimerRef	timer(t->thisP);

				timer->r.func(timer->r.arg, fired);
			}

		private:
			HANDLE				m_TimerQueueFd;;
			static sync::Mutex	m_MutexFd;
		};

		sync::Mutex	TimerQueue::m_MutexFd;

		void Init()
		{
			sync::MutexLockGuard	lock(TimerQueue::m_MutexFd);

			if (timerQueue == nullptr){
				timerQueue.reset(new TimerQueue());
			}
		}

		TimerRef NewTimer(Duration d, TimerFunc f, void *arg, error_t &err)
		{
			Init();
			return timerQueue->NewTimer(d, f, arg, err);
		}


		runtimeTimer::runtimeTimer()
			:when(0),
			period(0),
			func(NULL),
			arg(NULL),
			timerfd(INVALID_HANDLE_VALUE)
		{
		}

		bool Timer::Stop(error_t &err)
		{
			timerQueue->StopTimer(*this, err);

			return err == nullptr ? true : false;
		}



	}
}